package api

import (
	"context"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"mxshop_api/user_web/forms"
	"mxshop_api/user_web/global"
	"mxshop_api/user_web/global/response"
	"mxshop_api/user_web/middlewares"
	"mxshop_api/user_web/models"
	"mxshop_api/user_web/proto"
	"mxshop_api/user_web/utils"
	"net/http"
	"strconv"
	"strings"
	"time"
)

//将grpc的code转换成http的状态码
func HandleGrpcErrorToHttp(c *gin.Context, err error) {
	if err != nil {
		if e, ok := status.FromError(err); ok {
			switch e.Code() {
			case codes.NotFound:
				utils.ResJson(c, http.StatusNotFound, e.Message(), nil)
			case codes.Internal:
				utils.ResJson(c, http.StatusInternalServerError, "内部错误", nil)
			case codes.InvalidArgument:
				utils.ResJson(c, http.StatusBadRequest, "参数错误", nil)
			case codes.Unavailable:
				utils.ResJson(c, http.StatusInternalServerError, "用户服务不可用", nil)
			case codes.AlreadyExists:
				utils.ResJson(c, http.StatusInternalServerError, "用户已存在", nil)
			default:
				utils.ResJson(c, http.StatusInternalServerError, e.Code(), nil)
			}
			return
		}
	}
}

func removeTopStruct(fileds map[string]string) map[string]string {
	rsp := map[string]string{}
	for field, err := range fileds {
		rsp[field[strings.Index(field, ".")+1:]] = err
	}
	return rsp
}

//封装验证不通过的错误信息
func HandleValidatorError(c *gin.Context, err error) {
	errs, ok := err.(validator.ValidationErrors)
	if !ok {
		utils.ResJson(c, http.StatusOK, err.Error(), nil)
	}
	utils.ResJson(c, http.StatusBadRequest, removeTopStruct(errs.Translate(global.Trans)), nil)
}

func GetUserList(c *gin.Context) {
	claims, _ := c.Get("claims")
	currentUser := claims.(*models.CustomClaims)
	zap.S().Infof("当前访问的用户：%v", currentUser.Id)

	page := c.DefaultQuery("page", "0")
	limit := c.DefaultQuery("limit", "10")
	pageInt, _ := strconv.Atoi(page)
	limitInt, _ := strconv.Atoi(limit)

	userList, err := global.UserSrvClient.GetUserList(context.Background(), &proto.PageRequest{
		Page:     uint32(pageInt),
		PageSize: uint32(limitInt),
	})
	if err != nil {
		zap.S().Errorw("[GetUserList] 查询 【用户列表】失败")
		HandleGrpcErrorToHttp(c, err)
		return
	}

	result := make([]interface{}, 0)
	for _, value := range userList.Data {
		user := response.User{
			Id:       value.Id,
			NickName: value.NickName,
			Birthday: time.Unix(int64(value.BirthDay), 0).Format("2006-01-02"),
			Gender:   value.Gender,
			Mobile:   value.Mobile,
		}
		result = append(result, user)
	}

	reMap := gin.H{
		"total": userList.Total,
		"list":  result,
	}
	utils.ResJson(c, http.StatusOK, "", reMap)
}

func Login(c *gin.Context) {
	//表单验证
	loginForms := forms.LoginForm{}
	if err := c.ShouldBind(&loginForms); err != nil {
		HandleValidatorError(c, err)
		return
	}

	//登录逻辑
	user, err := global.UserSrvClient.GetUserByMobile(context.Background(), &proto.MobileRequest{
		Mobile: loginForms.Mobile,
	})
	if err != nil {
		if e, ok := status.FromError(err); ok {
			switch e.Code() {
			case codes.NotFound:
				utils.ResJson(c, http.StatusBadRequest, "用户不存在", nil)
			default:
				utils.ResJson(c, http.StatusInternalServerError, "登录失败", nil)
			}
			return
		}
	} else {
		//只是查询到用户了而已，并没有检查密码
		rsp, err := global.UserSrvClient.CheckPassWord(context.Background(), &proto.PasswordCheckRequest{
			Password:          loginForms.Password,
			EncryptedPassword: user.PassWord,
		})
		if err != nil {
			utils.ResJson(c, http.StatusInternalServerError, "登录失败", nil)
			return
		}

		if !rsp.Success {
			utils.ResJson(c, http.StatusBadRequest, "密码错误", nil)
			return
		}
		j := middlewares.NewJWT()
		claims := models.CustomClaims{
			ID:          uint(user.Id),
			NickName:    user.NickName,
			AuthorityId: uint(user.Role),
			StandardClaims: jwt.StandardClaims{
				NotBefore: time.Now().Unix(),               //签名的生效时间
				ExpiresAt: time.Now().Unix() + 60*60*24*30, //30天过期
				Issuer:    "imooc",
			},
		}
		token, err := j.CreateToken(claims)
		if err != nil {
			utils.ResJson(c, http.StatusInternalServerError, "生成token失败", nil)
			return
		}
		utils.ResJson(c, http.StatusOK, "登录成功", token)
	}
}

func Register(c *gin.Context) {
	//表单验证
	registerForm := forms.RegisterForm{}
	if err := c.ShouldBind(&registerForm); err != nil {
		HandleValidatorError(c, err)
		return
	}

	user, err := global.UserSrvClient.CreateUser(context.Background(), &proto.CreateUserRequest{
		NickName: registerForm.Mobile,
		PassWord: registerForm.Password,
		Mobile:   registerForm.Mobile,
	})
	if err != nil {
		zap.S().Infof("[Register] 调用【新建用户服务】失败", err.Error())
		HandleGrpcErrorToHttp(c, err)
		return
	}

	j := middlewares.NewJWT()
	claims := models.CustomClaims{
		ID:          uint(user.Id),
		NickName:    user.NickName,
		AuthorityId: uint(user.Role),
		StandardClaims: jwt.StandardClaims{
			NotBefore: time.Now().Unix(),               //签名的生效时间
			ExpiresAt: time.Now().Unix() + 60*60*24*30, //30天过期
			Issuer:    "imooc",
		},
	}
	token, err := j.CreateToken(claims)
	if err != nil {
		utils.ResJson(c, http.StatusInternalServerError, "生成token失败", nil)
		return
	}
	utils.ResJson(c, http.StatusOK, "注册成功", token)
}
